package com.pmcc.utils;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.beans.PropertyDescriptor;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;


/**
 * 对象的属性复制
 * 
 * @author wp
 *
 */
public abstract class BeanUtils extends org.springframework.beans.BeanUtils {

	/**
	 * 把一个对象的所有值不为空的属性的值赋值到另一个对象的同名属性
	 * 
	 * @param source
	 * @param target
	 * @throws BeansException
	 */
	public static void copyProperties(Object source, Object target) throws BeansException {
		Assert.notNull(source, "Source must not be null");
		Assert.notNull(target, "Target must not be null");
		Class<?> actualEditable = target.getClass();
		PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
		for (PropertyDescriptor targetPd : targetPds) {
			if (targetPd.getWriteMethod() != null) {
				PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
				if (sourcePd != null && sourcePd.getReadMethod() != null) {
					try {
						Method readMethod = sourcePd.getReadMethod();
						if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
							readMethod.setAccessible(true);
						}
						Object value = readMethod.invoke(source);
						// 这里判断以下value是否为空 当然这里也能进行一些特殊要求的处理 例如绑定时格式转换等等
						if (value != null) {
							Method writeMethod = targetPd.getWriteMethod();
							if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
								writeMethod.setAccessible(true);
							}
							writeMethod.invoke(target, value);
						}
					} catch (Throwable ex) {
						throw new FatalBeanException("Could not copy properties from source to target", ex);
					}
				}
			}
		}
	}

	public static String getRequestPayload(HttpServletRequest req) {
		StringBuilder sb = new StringBuilder();
		try {
			BufferedReader reader = req.getReader();
			char[] buff = new char[1024];
			int len;
			while ((len = reader.read(buff)) != -1) {
				sb.append(buff, 0, len);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		String result = sb.toString();
		if (result.startsWith("{"))
			result = '[' + result + ']';// to Array
		return result;
	}


	/**
	 * 从request中获取不为空的数据放到持久对象中
	 * @param bean
	 * @param request
	 */
	public static void setBeanData(Object bean, HttpServletRequest request){
		Class clazz = bean.getClass();
		Method ms[] = clazz.getDeclaredMethods();
		String mname;
		String field;
		String fieldType;

		Map map=request.getParameterMap();
		Set keSet=map.entrySet();
		for(Iterator itr=keSet.iterator();itr.hasNext();){
			String value = "";
			Map.Entry me=(Map.Entry)itr.next();
			Object ok=me.getKey();
			Object ov=me.getValue();
			String[] ovvalue=new String[1];
			if(ov instanceof String[]){
				ovvalue=(String[])ov;
			}else{
				ovvalue[0]=ov.toString();
			}

			for(int k=0;k<ovvalue.length;k++){
				value = ovvalue[k];
			}
			for(Method m : ms){
				mname = m.getName();
				if (!mname.startsWith("set") || ArrayUtils.isEmpty(m.getParameterTypes())) {
					continue;
				}
				try {
					field = mname.toLowerCase().charAt(3) + mname.substring(4, mname.length());
					if(ok.equals(field)){
//						if (StringUtils.isEmpty(value)) {
//							m.invoke(bean, value);
//							continue;
//						}
						fieldType = m.getParameterTypes()[0].getName();
						// 以下可以确认value为String类型
						if (String.class.getName().equals(fieldType)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (String)null);
							}else{
								m.invoke(bean, (String) value);
							}
						} else if (Integer.class.getName().equals(fieldType) && NumberUtils.isDigits((String) value)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (Integer)null);
							}else{
								m.invoke(bean, Integer.valueOf((String) value));
							}

						} else if (Short.class.getName().equals(fieldType) && NumberUtils.isDigits((String) value)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (Short)null);
							}else{
								m.invoke(bean, Short.valueOf((String) value));
							}
						} else if (Float.class.getName().equals(fieldType) && NumberUtils.isNumber((String) value)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (Float)null);
							}else{
								m.invoke(bean, Float.valueOf((String) value));
							}

						} else if (Double.class.getName().equals(fieldType) && NumberUtils.isNumber((String) value)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (Double)null);
							}else{
								m.invoke(bean, Double.valueOf((String) value));
							}

						} else if (Long.class.getName().equals(fieldType) && NumberUtils.isNumber((String) value)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (Long)null);
							}else{
								m.invoke(bean, Long.valueOf((String) value));
							}

						} else if (Date.class.getName().equals(fieldType)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (Date)null);
							}else{
								m.invoke(bean, DateUtils.parseDate((String) value, "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss"));
							}

						} else if (BigDecimal.class.getName().equals(fieldType)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (BigDecimal)null);
							}else{
								m.invoke(bean, BigDecimal.valueOf(Double.valueOf(value)));
							}

						} else {
							m.invoke(bean, value);
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
					continue;
				}
			}

		}
	}


	public static void setBeanData(Object bean, Map<String,String> map){
		Class clazz = bean.getClass();
		Method ms[] = clazz.getDeclaredMethods();
		String mname;
		String field;
		String fieldType;

		Set keSet=map.entrySet();
		for(Iterator itr=keSet.iterator();itr.hasNext();){
			String value = "";
			Map.Entry me=(Map.Entry)itr.next();
			Object ok=me.getKey();
			Object ov=me.getValue();
			String[] ovvalue=new String[1];
			if(ov instanceof String[]){
				ovvalue=(String[])ov;
			}else{
				ovvalue[0]=ov.toString();
			}

			for(int k=0;k<ovvalue.length;k++){
				value = ovvalue[k];
			}
			for(Method m : ms){
				mname = m.getName();
				if (!mname.startsWith("set") || ArrayUtils.isEmpty(m.getParameterTypes())) {
					continue;
				}
				try {
					field = mname.toLowerCase().charAt(3) + mname.substring(4, mname.length());
					if(ok.equals(field)){
//						if (StringUtils.isEmpty(value)) {
//							m.invoke(bean, value);
//							continue;
//						}
						fieldType = m.getParameterTypes()[0].getName();
						// 以下可以确认value为String类型
						if (String.class.getName().equals(fieldType)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (String)null);
							}else{
								m.invoke(bean, (String) value);
							}
						} else if (Integer.class.getName().equals(fieldType) && NumberUtils.isDigits((String) value)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (Integer)null);
							}else{
								m.invoke(bean, Integer.valueOf((String) value));
							}

						} else if (Short.class.getName().equals(fieldType) && NumberUtils.isDigits((String) value)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (Short)null);
							}else{
								m.invoke(bean, Short.valueOf((String) value));
							}
						} else if (Float.class.getName().equals(fieldType) && NumberUtils.isNumber((String) value)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (Float)null);
							}else{
								m.invoke(bean, Float.valueOf((String) value));
							}

						} else if (Double.class.getName().equals(fieldType) && NumberUtils.isNumber((String) value)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (Double)null);
							}else{
								m.invoke(bean, Double.valueOf((String) value));
							}

						} else if (Long.class.getName().equals(fieldType) && NumberUtils.isNumber((String) value)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (Long)null);
							}else{
								m.invoke(bean, Long.valueOf((String) value));
							}

						} else if (Date.class.getName().equals(fieldType)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (Date)null);
							}else{
								m.invoke(bean, DateUtils.parseDate((String) value, "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss"));
							}

						} else if (BigDecimal.class.getName().equals(fieldType)) {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, (BigDecimal)null);
							}else{
								m.invoke(bean, BigDecimal.valueOf(Double.valueOf(value)));
							}
						} else {
							if(StringUtils.isEmpty(value)){
								m.invoke(bean, null);
							}else{
								m.invoke(bean, value);
							}
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
					continue;
				}
			}

		}
	}

}
